﻿using System;
using System.Collections.Generic;
using System.Xml;
using Td.Additional.ComponentModel;

namespace Td.Additional.Xml
{
    internal class XmlWritePropertiesProcess
    {
        internal List<Object> ReferenceObjects = new List<object>();

        internal List<Object> Objects = new List<object>();

        internal List<XmlElement> Elements = new List<XmlElement>();

        internal List<Exception> Exceptions = new List<Exception>();

        internal List<Type> TypeOrder = new List<Type>();

        /// <summary>
        /// Adds a new reference object.
        /// </summary>
        /// <param name="obj">The obj.</param>
        internal void AddReferenceObject(Object obj)
        {
            if (obj == null)
                return;
            ReferenceObjects.Add(obj);
            Type type = obj.GetType();
            object[] attr = type.GetCustomAttributes(typeof(IdAttribute), true);
            XmlElement element = null;
            if (attr.Length > 0)
                while ((element = GetElementByObject(obj)) != null)
                {
                    var idAttribute = attr[0] as IdAttribute;
                    element.RemoveAll();
                    element.IsEmpty = true;
                    element.SetAttribute(Xml._ObjectIdDescriptor, type.InvokeMember(idAttribute.IdPropertyName, System.Reflection.BindingFlags.GetProperty, null, obj, null).ToString());
                    element.SetAttribute(Xml._TypeDescriptor, type.ToString());
                    DeleteObject(element);
                }
        }

        internal Boolean AddObject(Object obj, XmlElement element)
        {
            var index = ReferenceObjects.IndexOf(obj);
            if (index >= 0)
            {
                Type type = obj.GetType();
                object[] attr = type.GetCustomAttributes(typeof(IdAttribute), true);
                if (attr.Length > 0)
                {
                    var idAttribute = attr[0] as IdAttribute;
                    element.RemoveAll();
                    element.IsEmpty = true;
                    element.SetAttribute(Xml._ObjectIdDescriptor, type.InvokeMember(idAttribute.IdPropertyName, System.Reflection.BindingFlags.GetProperty, null, obj, null).ToString());
                    element.SetAttribute(Xml._TypeDescriptor, type.ToString());
                    return false;
                }
            }
            Objects.Add(obj);
            Elements.Add(element);
            return true;
        }

        internal XmlElement GetElementByObject(Object obj)
        {
            int index = Objects.IndexOf(obj);
            if (index >= 0)
                return Elements[index];
            return null;
        }

        internal void DeleteObject(Object obj)
        {
            int index = Objects.IndexOf(obj);
            if (index >= 0)
            {
                Objects.RemoveAt(index);
                Elements.RemoveAt(index);
            }
            else
            {
                index = Elements.IndexOf(obj as XmlElement);
                if (index >= 0)
                {
                    Objects.RemoveAt(index);
                    Elements.RemoveAt(index);
                }
            }
        }
    }
}